package redis

import (
	"encoding/json"
	"fmt"
	"github.com/edgexfoundry/edgex-go/internal/app/models"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/errors"
	"github.com/gomodule/redigo/redis"
)

const (
	ProductFunctionCollection          = "md|pf"
	ProductFunctionCollectionProductId = ProductFunctionCollection + DBKeySeparator + "productid"
)

// 创建产品功能redis键
func productFunctionStoreKey(id string) string {
	return CreateKey(ProductFunctionCollection, id)
}

// 检查产品功能id是否存在
func productFunctionIdExists(conn redis.Conn, id string) (bool, errors.EdgeX) {
	exists, err := objectIdExists(conn, productFunctionStoreKey(id))
	if err != nil {
		return false, errors.NewCommonEdgeX(errors.KindDatabaseError, "product function existence check by id failed", err)
	}
	return exists, nil
}

// productFunctionById 通过id查询产品功能
func productFunctionById(conn redis.Conn, id string) (productFunction models.ProductFunction, edgeXerr errors.EdgeX) {
	edgeXerr = getObjectById(conn, productFunctionStoreKey(id), &productFunction)
	if edgeXerr != nil {
		return productFunction, errors.NewCommonEdgeXWrapper(edgeXerr)
	}
	return
}

// 向redis中存储产品功能
func sendAddProductFunctionCmd(conn redis.Conn, storeKey string, pf models.ProductFunction) errors.EdgeX {
	dsJSONBytes, err := json.Marshal(pf)
	if err != nil {
		return errors.NewCommonEdgeX(errors.KindContractInvalid, "unable to JSON marshal product function for Redis persistence", err)
	}
	// md|pf:产品功能id        字符串
	_ = conn.Send(SET, storeKey, dsJSONBytes)
	// md|pf:productid:产品id  有序数组
	_ = conn.Send(ZADD, CreateKey(ProductFunctionCollectionProductId, pf.ProductId), 0, storeKey)

	return nil
}

// 从redis中删除产品功能
func sendDeleteProductFunctionCmd(conn redis.Conn, storeKey string, pf models.ProductFunction) errors.EdgeX {
	// md|pf:产品功能id        字符串
	_ = conn.Send(DEL, storeKey)
	// md|pf:productid:产品id  有序数组
	_ = conn.Send(ZREM, CreateKey(ProductFunctionCollectionProductId, pf.ProductId), storeKey)
	return nil
}

// addProductFunction 添加产品功能
func addProductFunction(conn redis.Conn, pf models.ProductFunction) (models.ProductFunction, errors.EdgeX) {
	// 检查产品功能id是否存在
	exists, edgeXerr := productFunctionIdExists(conn, pf.Id)
	if edgeXerr != nil {
		return pf, errors.NewCommonEdgeXWrapper(edgeXerr)
	} else if exists {
		return pf, errors.NewCommonEdgeX(errors.KindDuplicateName, fmt.Sprintf("product function id %s already exists", pf.Id), edgeXerr)
	}

	//ts := pkgCommon.MakeTimestamp()
	//if pf.CreateTime == 0 {
	//	pf.CreateTime = ts
	//}

	storeKey := productFunctionStoreKey(pf.Id)
	// 事务开始
	_ = conn.Send(MULTI)
	edgeXerr = sendAddProductFunctionCmd(conn, storeKey, pf)
	if edgeXerr != nil {
		return pf, errors.NewCommonEdgeXWrapper(edgeXerr)
	}
	// 事务结束
	_, err := conn.Do(EXEC)
	if err != nil {
		errors.NewCommonEdgeX(errors.KindDatabaseError, "product function failed", err)
	}
	return pf, edgeXerr
}

// 通过产品id查询产品功能
func AllFunctionsByProductId(conn redis.Conn, offset int, limit int, productId string) (productFunctions []models.ProductFunction, edgeXerr errors.EdgeX) {
	// 分页查询该产品的功能
	objects, edgeXerr := getObjectsByRange(conn, CreateKey(ProductFunctionCollectionProductId, productId), offset, limit)
	if edgeXerr != nil {
		return productFunctions, errors.NewCommonEdgeXWrapper(edgeXerr)
	}
	// 将返回值转换为产品功能数组
	productFunctions = make([]models.ProductFunction, len(objects))
	for i, in := range objects {
		pf := models.ProductFunction{}
		err := json.Unmarshal(in, &pf)
		if err != nil {
			return []models.ProductFunction{}, errors.NewCommonEdgeXWrapper(err)
		}
		productFunctions[i] = pf
		for j, v := range pf.Command.ResourceOperations {
			pa, errx := ProductAttributeById(conn, v.ProductResourceId)
			if errx != nil {
				return productFunctions, errors.NewCommonEdgeXWrapper(err)
			}
			productFunctions[i].Command.ResourceOperations[j].ProductResource = pa.Resource.Name
			productFunctions[i].Command.ResourceOperations[j].Code = pa.Resource.Code
			productFunctions[i].Command.ResourceOperations[j].ValueType = pa.Resource.Properties.ValueType
		}
	}
	return productFunctions, nil
}

// 批量删除产品功能
func ProductFunctionDelete(conn redis.Conn, productFunctionIds []string) errors.EdgeX {
	var productFunctions []models.ProductFunction
	for _, id := range productFunctionIds {
		// 通过id查询产品功能
		functionById, err := productFunctionById(conn, id)
		if err != nil {
			return errors.NewCommonEdgeXWrapper(err)
		}
		productFunctions = append(productFunctions, functionById)
	}
	// 事务开始
	_ = conn.Send(MULTI)
	for i, id := range productFunctionIds {
		storeKey := productFunctionStoreKey(id)
		err := sendDeleteProductFunctionCmd(conn, storeKey, productFunctions[i])
		if err != nil {
			return errors.NewCommonEdgeXWrapper(err)
		}
	}
	// 事务结束
	_, err := conn.Do(EXEC)
	if err != nil {
		return errors.NewCommonEdgeX(errors.KindDatabaseError, "product functions delete failed", err)
	}
	return nil
}

// 更新产品功能
func UpdateProductFunction(conn redis.Conn, pf models.ProductFunction) errors.EdgeX {
	// 通过id查询原产品功能
	oldFunction, err := productFunctionById(conn, pf.Id)
	if err != nil {
		return errors.NewCommonEdgeXWrapper(err)
	}
	//pf.CreateTime = oldFunction.CreateTime

	// 事务开始
	_ = conn.Send(MULTI)
	storeKey := productFunctionStoreKey(pf.Id)
	sendDeleteProductFunctionCmd(conn, storeKey, oldFunction)
	err = sendAddProductFunctionCmd(conn, storeKey, pf)
	if err != nil {
		return errors.NewCommonEdgeXWrapper(err)
	}
	// 事务结束
	_, err2 := conn.Do(EXEC)
	if err2 != nil {
		return errors.NewCommonEdgeXWrapper(err2)
	}
	return nil
}
